// synch.cc 
//	Routines for synchronizing threads.  Three kinds of
//	synchronization routines are defined here: semaphores, locks 
//   	and condition variables (the implementation of the last two
//	are left to the reader).
//
// Any implementation of a synchronization routine needs some
// primitive atomic operation.  We assume Nachos is running on
// a uniprocessor, and thus atomicity can be provided by
// turning off interrupts.  While interrupts are disabled, no
// context switch can occur, and thus the current thread is guaranteed
// to hold the CPU throughout, until interrupts are reenabled.
//
// Because some of these routines might be called with interrupts
// already disabled (Semaphore::V for one), instead of turning
// on interrupts at the end of the atomic operation, we always simply
// re-set the interrupt state back to its original value (whether
// that be disabled or enabled).
//
// Copyright (c) 1992-1993 The Regents of the University of California.
// All rights reserved.  See copyright.h for copyright notice and limitation 
// of liability and disclaimer of warranty provisions.

#include "copyright.h"
#include "synch.h"
#include "system.h"
//----------------------------------------------------------------------
// Semaphore::Semaphore
// 	Initialize a semaphore, so that it can be used for synchronization.
//
//	"debugName" is an arbitrary name, useful for debugging.
//	"initialValue" is the initial value of the semaphore.
//----------------------------------------------------------------------

Semaphore::Semaphore(char* debugName, int initialValue)
{
    name = debugName;
    value = initialValue;
    queue = new List;
}

//----------------------------------------------------------------------
// Semaphore::Semaphore
// 	De-allocate semaphore, when no longer needed.  Assume no one
//	is still waiting on the semaphore!
//----------------------------------------------------------------------

Semaphore::~Semaphore()
{
    delete queue;
}

//----------------------------------------------------------------------
// Semaphore::P
// 	Wait until semaphore value > 0, then decrement.  Checking the
//	value and decrementing must be done atomically, so we
//	need to disable interrupts before checking the value.
//
//	Note that Thread::Sleep assumes that interrupts are disabled
//	when it is called.
//----------------------------------------------------------------------

void
Semaphore::P()
{
    IntStatus oldLevel = interrupt->SetLevel(IntOff);	// disable interrupts
    
    while (value == 0) { 			// semaphore not available
	queue->Append((void *)currentThread);	// so go to sleep
	currentThread->Sleep();
    } 
    value--; 					// semaphore available, 
						// consume its value
    
    (void) interrupt->SetLevel(oldLevel);	// re-enable interrupts
}

//----------------------------------------------------------------------
// Semaphore::V
// 	Increment semaphore value, waking up a waiter if necessary.
//	As with P(), this operation must be atomic, so we need to disable
//	interrupts.  Scheduler::ReadyToRun() assumes that threads
//	are disabled when it is called.
//----------------------------------------------------------------------

void
Semaphore::V()
{
    Thread *thread;
    IntStatus oldLevel = interrupt->SetLevel(IntOff);

    thread = (Thread *)queue->Remove();
    if (thread != NULL)	   // make thread ready, consuming the V immediately
	scheduler->ReadyToRun(thread);
    value++;
    (void) interrupt->SetLevel(oldLevel);
}

//----------------------------------------------------------------------
// Lock::Lock
// 	Initialize a lock, so that it can be used for synchronization.
//
//	"debugName" is an arbitrary name, useful for debugging.
//----------------------------------------------------------------------
Lock::Lock() 
{
	name = "anonymity";
	lockQueue = new List;
	lockStateBusy = false;	// initial lock as FREE and nobody owns it
	lockOwner = NULL;
}

Lock::Lock(char* debugName) 
{
	name = debugName;
	lockQueue = new List;
	lockStateBusy = false;	// initial lock as FREE and nobody owns it
	lockOwner = NULL;
}

//----------------------------------------------------------------------
// Lock::Lock
// 	De-allocate lock, when no longer needed.  Assume no one
//	is still waiting on the lock!
//----------------------------------------------------------------------
Lock::~Lock() 
{
	delete lockQueue;
}

//----------------------------------------------------------------------
// Lock::Acquire
// 	Check the lockStateBusy, if false then	
//		Wait until other thread pass the lock to the current thread.
//	if true then 
//		Check the lockStateBusy and set it to be true
//
//	Checking the lockStateBusy and setting it to be true must be 
//	done atomically, so we need to disable interrupts before checking lockStateBusy.
//
//	Note that Thread::Sleep assumes that interrupts are disabled
//	when it is called.
//----------------------------------------------------------------------

void Lock::Acquire() 
{	
	IntStatus oldLevel = interrupt->SetLevel(IntOff);	// disable interrupts
	if(isHeldByCurrentThread() == true){	// current thread owns the lock
		(void) interrupt->SetLevel(oldLevel);	// restore interrupts and return
		return;
	}
	if(lockStateBusy != true){	// lock available
		lockStateBusy = true;		//make lock busy 
		lockOwner = currentThread;	//make current thread owner
	}else{	// lock not available
		lockQueue->Append((void *)currentThread);	// make current thread wait in the queue
		currentThread->Sleep();						// put current thread to sleep
	}
	(void) interrupt->SetLevel(oldLevel);	// restore interrupts and return
	return;
}

//----------------------------------------------------------------------
// Lock::Release
// 	Pass the current lock to the next thread waiting in the queue
//	and wake it up.
//
//	As with Acquire(), this operation must be atomic, so we need to disable
//	interrupts.  Scheduler::ReadyToRun() assumes that threads
//	are disabled when it is called.
//----------------------------------------------------------------------

void Lock::Release() 
{
	Thread *thread;
	IntStatus oldLevel = interrupt->SetLevel(IntOff);	// disable interrupts
	if(isHeldByCurrentThread() == false){	// current thread doesn't own the lock
		
		printf("%s: WARNING: not the owner of ", currentThread->getName());	// print error message
		printf("Lock: %s when executing Lock:: Release(). \n", name);
		(void) interrupt->SetLevel(oldLevel);	//restore interrupts and return
		return;
	}
	thread = (Thread *) lockQueue->Remove();
	if(thread != NULL ){	//if a thread is waiting
		scheduler->ReadyToRun(thread);	// make the thread ready and lock owner
		lockOwner = thread;
	}else{	//no thread is waiting
		lockStateBusy = false;	// free the lock and clear the lock ownership
		lockOwner = NULL;
	}
	(void) interrupt->SetLevel(oldLevel);	//restore interrupts and return
}

//----------------------------------------------------------------------
// Lock::isHeldBycurrentThread
//	true if the current thread holds this lock.  Useful for
// checking in Release, and in Condition variable ops below.
//----------------------------------------------------------------------

bool Lock::isHeldByCurrentThread()
{	
	bool isOwner = false;
	if(currentThread == lockOwner)
		isOwner = true;
	
	return isOwner;
}
//----------------------------------------------------------------------
// Condition::Condition
// 	Initialize a condition variable, so that it can be used for 
//	synchronization.
//
//	"debugName" is an arbitrary name, useful for debugging.
//----------------------------------------------------------------------

Condition::Condition() 
{
	name = "anonymity";
	waitingLock = NULL;	//initialize the condition to be "no one waiting"
	cvQueue = new List;
}

Condition::Condition(char* debugName) 
{
	name = debugName;
	waitingLock = NULL;	//initialize the condition to be "no one waiting"
	cvQueue = new List;
}

//----------------------------------------------------------------------
// Condition::Condition
// 	De-allocate condition variable, when no longer needed.  Assume no one
//	is still waiting in the condition variable queue!
//----------------------------------------------------------------------
Condition::~Condition() 
{ 
	delete cvQueue;
}

//----------------------------------------------------------------------
// Condition::Wait
// 	Wait in the condition variable queue until another thread calls
//	Signal()
//	"conditionLock" is a lock to make the operating on the condition
//					variable Mutual Exclusive
//	
//	Note that Thread::Sleep assumes that interrupts are disabled
//	when it is called.
//----------------------------------------------------------------------

void Condition::Wait(Lock* conditionLock) 
{ 
	IntStatus oldLevel = interrupt->SetLevel(IntOff);	// disable interrupts
	if(conditionLock == NULL){	// Null lock for the condition variable
								// print error message
		printf("%s: WARNING: input NULL lock ", currentThread->getName());	
		printf("when executing Condition::Wait(Lock *). \n");
	
		(void) interrupt->SetLevel(oldLevel);	// restore interrupts and return
		return;
	}
	
	if(conditionLock->isHeldByCurrentThread() == false){	// current thread doesn't own the lock
								// print error message
		printf("%s: WARNING: not the owner of Lock: ", currentThread->getName());	
		printf("%s when executing Condition::Wait(Lock *). \n",conditionLock->getName());
		
		(void) interrupt->SetLevel(oldLevel);	//restore interrupts and return
		return;
	}
	
	if(waitingLock == NULL){	// current thread is the first waiting thread
		waitingLock = conditionLock;
	}
	if(conditionLock != waitingLock){	// wrong entry lock for this condition variable
									// print error message
		printf("%s: WARNING: input wrong entry lock ", currentThread->getName());	
		printf("when executing Condition::Wait(Lock *). \n");
		printf("	input lock: %s\n", conditionLock->getName());
		printf("	entry lock: %s\n", waitingLock->getName());

		(void) interrupt->SetLevel(oldLevel);	// restore interrupts and return
		return;
	}
	//Ok to wait
	conditionLock->Release();	// exit critical section of conditionLock
	cvQueue->Append((void *)currentThread);	// wait for the condition variable
	currentThread->Sleep();
	conditionLock->Acquire();	// reenter critical section

	(void) interrupt->SetLevel(oldLevel);	// restore interrupts and wait
	return;
}

//----------------------------------------------------------------------
// Condition::Signal
// 	Wake up on thread that is waiting in the condition variable queue if
//	there is one.
//	
//	"conditionLock" is a lock to make the operating on the condition
//					variable Mutual Exclusive
//
//	As with Wait(), this operation must be atomic, so we need to disable
//	interrupts.  Scheduler::ReadyToRun() assumes that threads
//	are disabled when it is called.
//----------------------------------------------------------------------


void Condition::Signal(Lock* conditionLock) 
{ 
	Thread *thread;
	IntStatus oldLevel = interrupt->SetLevel(IntOff);	// disable interrupts
	
	if(conditionLock->isHeldByCurrentThread() == false){	// current thread doesn't own the lock
									// print error message
		printf("%s: WARNING: not the owner of Lock: ", currentThread->getName());	
		printf("%s when executing Condition::Signal(Lock *). \n",conditionLock->getName());
	
		(void) interrupt->SetLevel(oldLevel);	//restore interrupts and return
		return;
	}
	if(waitingLock == NULL){	// no thread waiting
		(void) interrupt->SetLevel(oldLevel);	// restore interrupts and return
		return;
	}
	if(conditionLock != waitingLock){	// wrong entry lock for this condition variable
									// print error message
		printf("%s: WARNING: input wrong entry lock ", currentThread->getName());	
		printf("when executing Condition::Signal(Lock *). \n");
		printf("	Input lock: %s\n", conditionLock->getName());	
		printf("	Waitinglock: %s\n", waitingLock->getName());
		
		(void) interrupt->SetLevel(oldLevel);	// restore interrupts and return
		return;
	}
	
	// wake up 1 waiting thread	
	thread = (Thread *) cvQueue->Remove();
	scheduler->ReadyToRun(thread);	// make it ready
	
	if(cvQueue->IsEmpty() == true){	// no more waiting threads
		waitingLock = NULL;
	}
	
	(void) interrupt->SetLevel(oldLevel);	// restore interrupts and return
	return;
}

//----------------------------------------------------------------------
// Condition::Broadcast
// 	Wake up all the threads that are waiting in the condition variable 
//	queue.
//	
//	"conditionLock" is a lock to make the operating on the condition
//					variable Mutual Exclusive
//
//	Since we have implemented disabling interrupts in Signal when waking
//	up each thread. So we do not need to disable interrupts here.
//----------------------------------------------------------------------

void Condition::Broadcast(Lock* conditionLock) 
{ 
	while(cvQueue->IsEmpty() == false){	// there are waiting threads
		Signal(conditionLock);	// wake up one thread
	}
	return;
}



#ifdef NETWORK
//--------------------------Project3 Part3 ServerLock-------------------------------------

ServerLock::ServerLock() 
{
	serverLockName = "anonymity";
	printf("Fatal Error: ServerLock Constructor: the ServerLock do not have the name!\n");
	serverLockQueue = new List();
	serverLockStateBusy = false;	// initial lock as FREE and nobody owns it
	serverLockOwner = NULL;
}


ServerLock::ServerLock(char* name) 
{
	serverLockName=new char[MAXSTRINGLENGTH];
	strcpy(serverLockName,name);
	serverLockQueue = new List();
	serverLockStateBusy = false;	// initial lock as FREE and nobody owns it
	serverLockOwner = NULL;
}

ServerLock::~ServerLock() 
{
	delete serverLockQueue;
	delete serverLockName;
}

int ServerLock::ServerLockAcquire(struct Socket* subjectSocket) 
{	
	//printf("myDebug: the socket is %d+%d\n", subjectSocket->machineID, subjectSocket->mailboxNum);
	if(isHeldByCurrentSocket(subjectSocket) == true){	
	// current Socket owns the lock
		printf("rpcDebug:I am already the lock owner\n");
		return IAMLOCKOWNER;
	}
	
	
	if(serverLockStateBusy != true){	// lock available
		serverLockStateBusy = true;		//make lock busy 
		serverLockOwner = subjectSocket;	//make current thread owner
		return SUCCAQUR; //Acquire Successful: Send the reply
	}else{	// lock not available
		serverLockQueue->Append((void *)subjectSocket);	// make current thread wait in the queue											
		return WAITINQUEUE;
	}
	
}


struct Socket* ServerLock::ServerLockRelease(struct Socket* subjectSocket) 
{
	struct Socket *releasedSocket;

	if(isHeldByCurrentSocket(subjectSocket) == false){	// current socket doesn't own the lock
		
		printf("WARNING: machine %d with mailbox %d is not the owner of ",subjectSocket->machineID,subjectSocket->mailboxNum);	// print error message
		printf("Lock: %s when executing Lock:: Release(). \n", serverLockName);
		return NULL;
	}
	releasedSocket = (struct Socket *) serverLockQueue->Remove();
	if(releasedSocket != NULL ){	//if a thread is waiting
		//scheduler->ReadyToRun(thread);	// make the thread ready and lock owner
		serverLockOwner = releasedSocket;
		return releasedSocket;
	}else{	//no thread is waiting
		serverLockStateBusy = false;	// free the lock and clear the lock ownership
		serverLockOwner = NULL;
		return NULL;
	}
}


bool ServerLock::isHeldByCurrentSocket(struct Socket* subjectSocket)
{	
	if(serverLockOwner == NULL) {
		return false;
	}
	printf("myDebug: the owner is %d+%d; the subject is %d+%d\n",serverLockOwner->machineID,serverLockOwner->mailboxNum,subjectSocket->machineID,subjectSocket->mailboxNum);
	if(serverLockOwner->machineID == subjectSocket->machineID && serverLockOwner->mailboxNum == subjectSocket->mailboxNum){
		return true;
	}
	
	return false;
}


ServerCondition::ServerCondition() 
{
	serverConditionName = "anonymity";
	printf("Fatal Error: ServerCondition Constructor: the ServerCondition do not have the name!\n");
	serverLockIndex = -1;	//initialize the condition to be "no one waiting"
	serverConditionQueue = new List();
}

ServerCondition::ServerCondition(char* name) 
{
	serverConditionName=new char[MAXSTRINGLENGTH];
	strcpy(serverConditionName,name);
	serverLockIndex = -1;	//initialize the condition to be "no one waiting"
	serverConditionQueue = new List();
}

ServerCondition::~ServerCondition() 
{ 
	delete serverConditionQueue;
	delete serverConditionName;
}


struct Socket* ServerCondition::ServerConditionWait(int conditionLockIndex,struct Socket* subjectSocket)   //return the socket when release lock called
{ 
	
	
	if(conditionLockIndex == -1){	// Null lock for the condition variable
								// print error message
		printf("WARNING: input NULL lock of machine and mailbox ");	
		printf("when executing ServerCondition::ServerConditionWait(int conditionLockIndex,struct Socket* subjectSocket) \n");
		return NULL;
	}
	
	
	if(ServerLockTable[conditionLockIndex].theServerLock->isHeldByCurrentSocket(subjectSocket) == false){	// current socket doesn't own the lock
								// print error message
		printf("WARNING: not the owner of Lock: ");	
		printf("%s when executing ServerCondition::ServerConditionWait(int conditionLockIndex,struct Socket* subjectSocket). \n",ServerLockTable[conditionLockIndex].theServerLock->serverLockName);
		return NULL;
	}
	
	if(serverLockIndex == -1){	// current socket is the first waiting socket
		serverLockIndex = conditionLockIndex;
	}
	if(conditionLockIndex != serverLockIndex){	// wrong entry lock for this condition variable
									// print error message
		printf("WARNING: input wrong entry lock ");	
		printf("when executing ServerCondition::ServerConditionWait(int conditionLockIndex,struct Socket* subjectSocket). \n");
		printf("	input lock: %s\n",ServerLockTable[conditionLockIndex].theServerLock->serverLockName);
		printf("	entry lock: %s\n", ServerLockTable[serverLockIndex].theServerLock->serverLockName);
		return NULL;
	}
	//Ok to wait
	struct Socket* releasedSocket;
	releasedSocket = ServerLockTable[conditionLockIndex].theServerLock->ServerLockRelease(subjectSocket);	// exit critical section of conditionLock
	printf("rpcDebug: Into CVQueue # is %d\n",subjectSocket->machineID);
	serverConditionQueue->Append((void *)subjectSocket);
	
//	currentThread->Sleep();
	//ServerLockTable[conditionLockIndex].theServerLock->ServerLockAcquire(subjectSocket) ; 
	

//(void) interrupt->SetLevel(oldLevel);	// restore interrupts and wait
	return releasedSocket; 
}


struct Socket* ServerCondition::ServerConditionSignal(int conditionLockIndex, struct Socket* subjectSocket) 
{ 
	struct Socket * wakedSocket;
	if(conditionLockIndex == -1){	// Null lock for the condition variable
								// print error message
		printf("WARNING: input NULL lock of machine and mailbox ");	
		printf("when executing ServerCondition::ServerConditionSignal(int conditionLockIndex,struct Socket* subjectSocket) \n");
		return NULL;
	}
	
	
	if(ServerLockTable[conditionLockIndex].theServerLock->isHeldByCurrentSocket(subjectSocket) == false){	// current thread doesn't own the lock
									// print error message
		printf("WARNING: not the owner of Lock: ");	
		printf("%s when executing ServerCondition::ServerConditionWait(int conditionLockIndex,struct Socket* subjectSocket). \n",ServerLockTable[conditionLockIndex].theServerLock->serverLockName);
		return NULL;
	}
	
	if(serverLockIndex == -1){	// no thread waiting
		printf("WARNING: no socket waiting");
		printf("%s when executing ServerCondition::ServerConditionWait(int conditionLockIndex,struct Socket* subjectSocket). \n",ServerLockTable[conditionLockIndex].theServerLock->serverLockName);
		return NULL;
	}
	
	if(conditionLockIndex != serverLockIndex){	// wrong entry lock for this condition variable
									// print error message
		printf("WARNING: input wrong entry lock ");	
		printf("when executing ServerCondition::ServerConditionSignal(int conditionLockIndex, struct Socket* subjectSocket). \n");
		printf("	input lock: %s\n",ServerLockTable[conditionLockIndex].theServerLock->serverLockName);
		printf("	waiting lock: %s\n", ServerLockTable[serverLockIndex].theServerLock->serverLockName);
		return NULL;
	}
	
	// wake up 1 waiting thread	
	wakedSocket = (struct Socket *) serverConditionQueue->Remove();
	printf("rpcDebug: Out CVQueue # is %d\n",wakedSocket->machineID);

	
	if(serverConditionQueue->IsEmpty() == true){	// no more waiting threads
		serverLockIndex = -1;
	}

	return wakedSocket;
}


int ServerCondition::ServerConditionBroadcast(int conditionLockIndex,struct Socket* subjectSocket) 
{ 
	while(serverConditionQueue->IsEmpty() == false){	// there are waiting threads
		struct Socket* wakedSocket;
		wakedSocket = ServerConditionSignal(conditionLockIndex,subjectSocket);	// wake up one thread
		if(wakedSocket != NULL) {
			//Send back the wakedSocket
			PacketHeader outPktHdr, inPktHdr;
			MailHeader outMailHdr, inMailHdr;
			char* sendData;
			RpcRplyMessage replyMessage;
		
			replyMessage.rplyType = WAITCV;
			replyMessage.status = IWASWAKEDUP;
			outPktHdr.to = wakedSocket->machineID;
			outMailHdr.to = wakedSocket->mailboxNum;
			
			outMailHdr.length = sizeof(replyMessage);
			sendData = (char*)(&replyMessage);	
			postOffice->Send(outPktHdr, outMailHdr, sendData);
		
		}

	
	}
	return OK;
}


#endif
